﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using SysMisc;

namespace Kernel
{
    public class Core
    {

        #region 数据库对象操作
        /// <summary>
        /// 由对象ObjectId打开对象
        /// </summary>
        /// <param name="id">ObjectId</param>
        /// <param name="mode">打开模式</param>
        /// <param name="db">数据库</param>
        /// <returns>数据库对象</returns>
        public static DBObject GetObject(ObjectId id, OpenMode mode, Database db = null)
        {
            DBObject obj = null;

            // 必须在一个事物中打开  
            using (Transaction tr = db.TransactionManager.StartTransaction()) // using内自动调用 tr.Dispose()  
            {
                obj = tr.GetObject(id, mode) as DBObject;
                tr.Commit(); // 提交事物， 事物内操作全部执行，否则在全部回滚。  
            }
      
            return obj;  
        }

        /// <summary>
        /// 要删除的对象
        /// </summary>
        /// <param name="obj"></param>
        public static void Remove(DBObject obj)
        {
            Database db = obj.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                obj.Erase(); // 删除一个实体  
                tr.Commit();
            }
        }


        /// <summary>
        /// 删除ObjectId集合中的对象
        /// </summary>
        /// <param name="ids">要删除的对象ObjectId集合</param>
        public static void Remove(ObjectIdCollection ids)
        {
            if (ids.Count == 0)
                return;

            // 获取实体所在数据  
            ObjectId id = ids[0];
            Database db = id.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // obj.Erase(); // 删除一个实体  
                Entity ent;
                foreach (ObjectId idTemp in ids)
                {
                    ent = tr.GetObject(idTemp, OpenMode.ForWrite) as Entity;
                    if (null != ent)
                        ent.Erase();
                }

                tr.Commit();
            }
        }

        public void Clone(ObjectIdCollection idCollection, ObjectId containerId, Database ndb)
        {
            Database odb = idCollection[0].Database;
            IdMapping map = new IdMapping();
            odb.WblockCloneObjects(idCollection, containerId, map, DuplicateRecordCloning.Replace, false);
        }

        // clone实体  
        public static void CloneEnt(ObjectIdCollection ids, ObjectId idOwn)
        {
            if (ids.Count == 0)
                return;

            Database dbSource = ids[0].Database;
            IdMapping idMap = new IdMapping();

            dbSource.WblockCloneObjects(ids, idOwn, idMap, DuplicateRecordCloning.Replace, false);
        }
        #endregion

        #region 文档相关
        /// <summary>
        /// 新建文档
        /// </summary>
        public static void NewDoc()
        {
            string strTemp = "acad.dwt"; // cad基本模板  
            Document docNew = Application.DocumentManager.Add(strTemp);

            Application.DocumentManager.MdiActiveDocument = docNew; // 设置为当前文档  
        }

        /// <summary>
        /// 得到当前活动文档
        /// </summary>
        /// <returns></returns>
        public static Document GetCurrentActiveDoc()
        {
            return Application.DocumentManager.MdiActiveDocument;
        }

        // 打开文件  
        public static Document OpenDoc(string strFileName)
        {
            Document doc = null;
            DocumentCollection acDcoMag = Application.DocumentManager;

            if (System.IO.File.Exists(strFileName))
            {
                try
                {
                    doc = acDcoMag.Open(strFileName);
                }
                catch (System.Exception e)
                {
                    LogHelper.Error(typeof(Core), e);
                    Application.ShowAlertDialog("\n 打开文件 \"" + strFileName + "\"失败！");
                }
            }
            else
            {
                Application.ShowAlertDialog("\n 文件 "+strFileName +  "不存在");
            }

            return doc;
        }

        public static Document GetDocFromOpenedFiles(string strFileFullName)
        {
            DocumentCollection acDcoMag = Application.DocumentManager;
            foreach (Document doc in acDcoMag)
            {
                if (doc.Name.Equals(strFileFullName))
                    return doc;
            }
            return null;
        }

        public static bool IsDocOpened( string strFileFullName)
        {
            DocumentCollection acDcoMag = Application.DocumentManager;
            foreach( Document doc in acDcoMag)
            {
                if (doc.Name.Equals(strFileFullName))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// 通过路径全名来返回对应的Document，如果已经打开则直接返回对象，没有打开则先打开，再返回对象。
        /// </summary>
        /// <param name="strFileFullName"></param>
        /// <returns></returns>
        public static Document GetDoc( string strFileFullName)
        {
            Document doc = GetDocFromOpenedFiles(strFileFullName);
            if( null == doc )
                doc = OpenDoc(strFileFullName);
            return doc;
        }
        #endregion

        #region Entity实体操作
        /// <summary>
        /// 将一个实体接入到指定的Database的模型空间
        /// </summary>
        /// <param name="ent">实体对象</param>
        /// <param name="db">数据库</param>
        /// <returns>对象ObjectId</returns>
        public static ObjectId AppendToModelSpace(Entity ent, Database db)
        {
            ObjectId id;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite);
                BlockTableRecord modeSpce = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                id = modeSpce.AppendEntity(ent);
                tr.AddNewlyCreatedDBObject(ent, true);
                tr.Commit();
            }
            return id;
        }


        /// <summary>
        /// 将一组实体加入到指定的Database的模型空间
        /// </summary>
        /// <param name="ents">要添加的对象集合</param>
        /// <param name="db">数据库</param>
        /// <returns>对象 ObjectId</returns>
        public static ObjectIdCollection AppendToModelSpace(DBObjectCollection ents, Database db)
        {
            ObjectIdCollection ids = new ObjectIdCollection();

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite);
                BlockTableRecord modeSpce = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                foreach (DBObject obj in ents)
                {
                    Entity ent = obj as Entity;
                    if (null != ent)
                    {
                        ids.Add(modeSpce.AppendEntity(ent));
                        tr.AddNewlyCreatedDBObject(ent, true);
                    }

                }

                tr.Commit();
            }
            return ids;
        }
        #endregion

        /// <summary>
        /// 将指定的块定义变成块参照添加到指定模型空间
        /// </summary>
        /// <param name="block">快定义</param>
        /// <param name="pt">插入点</param>
        /// <param name="db">数据库</param>
        /// <returns></returns>
        public ObjectId BlkInDb(BlockTableRecord block, Point3d pt, Database db)
        {

            BlockReference br = null;

            ObjectId id = new ObjectId();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                // 打开模型空间  
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord modeSpce = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                //  

                // 新建一个块引用  
                br = new BlockReference(pt, block.ObjectId);
                id = modeSpce.AppendEntity(br);
                tr.AddNewlyCreatedDBObject(br, true);

                // 遍历块记录中的所有实体，加入块引用中  
                foreach (ObjectId idTemp in block)
                {
                    //判断该实体是否是块定义 ，也可以以块定义方式打开，但是会产生事物嵌套
                    if (idTemp.GetType().Equals(typeof(AttributeDefinition)))//自己修改过的一个判断函数
                    {
                        AttributeDefinition adDef = tr.GetObject(idTemp, OpenMode.ForRead) as AttributeDefinition;
                        if (adDef != null)
                        {
                            AttributeReference ar = new AttributeReference(adDef.Position, adDef.TextString, adDef.Tag, new ObjectId());
                            br.AttributeCollection.AppendAttribute(ar);
                        }
                    }
                }

                tr.Commit();
            }

            return id;
        }

        #region ModelSpace模型空间操作
        /// <summary>
        /// 将一个实体加入到指定的Database的模型空间
        /// </summary>
        /// <param name="ent">实体对象</param>
        /// <param name="db">数据库</param>
        /// <returns>对象</returns>
        public ObjectId ToModelSpace(Entity ent, Database db)
        {
            ObjectId entId;
            using(Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord modelSpace = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                entId = modelSpace.AppendEntity(ent);
                trans.AddNewlyCreatedDBObject(ent, true);
                trans.Commit();
            }

            return entId;
        }

        /// <summary>
        /// 将一组实体加入到指定的Database的模型空间
        /// </summary>
        /// <param name="entCollection">要添加的对象集合</param>
        /// <param name="db">数据库</param>
        /// <returns>对象 ObjectId</returns>
        public ObjectIdCollection ToModelSpace(DBObjectCollection entCollection, Database db)
        {
            ObjectIdCollection objIds = new ObjectIdCollection();
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord modelSpace = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                foreach( DBObject obj in entCollection)
                {
                    Entity ent = obj as Entity;
                    if( ent != null)
                    {
                        objIds.Add(modelSpace.AppendEntity(ent));
                        trans.AddNewlyCreatedDBObject(ent, true);
                    }
                }
                trans.Commit();
            }
            return objIds;
        }

        /// <summary>
        /// 将指定的块定义变成块参照添加到指定模型空间
        /// </summary>
        /// <param name="block">快定义</param>
        /// <param name="pt">插入点</param>
        /// <param name="db">数据库</param>
        /// <returns>快参照</returns>
        public ObjectId ToModelSpace(BlockTableRecord block, Point3d pt, Database db)
        {
            BlockReference br = null;
            ObjectId blkrfid = new ObjectId();
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord modelSpace = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                br = new BlockReference(pt, block.ObjectId);//通过块定义，添加块参照
                blkrfid = modelSpace.AppendEntity(br);//把块参照添加到块表记录中
                trans.AddNewlyCreatedDBObject(br, true);

                foreach( ObjectId id in block)
                {
                    if (true)//对象类型判断
                    {
                        AttributeDefinition ad = trans.GetObject(id, OpenMode.ForRead) as AttributeDefinition;
                        AttributeReference ar = new AttributeReference(ad.Position, ad.TextString, ad.Tag, new ObjectId());
                        br.AttributeCollection.AppendAttribute(ar);
                    }
                }
                trans.Commit();
            }
            return blkrfid;
        }
        #endregion

        #region Layer图层操作
        /// <summary>
        /// 根据图层名获取图层
        /// </summary>
        /// <param name="strName">图层名</param>
        /// <param name="db">数据库对象</param>
        /// <returns></returns>
        public static LayerTableRecord GetLayer(string strName, Database db)
        {
            LayerTableRecord layer = new LayerTableRecord();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTableRecord layerTemp = new LayerTableRecord();
                LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                if (lt != null)
                {
                    if (lt.Has(strName))
                    {
                        layerTemp = tr.GetObject(lt[strName], OpenMode.ForRead) as LayerTableRecord;
                        if (null != layerTemp)
                        {
                            if (!layerTemp.IsErased)
                                layer = layerTemp;
                        }
                    }
                }

                tr.Commit();
            }
            return layer;
        }

        /// <summary>
        /// 获取当前图层
        /// </summary>
        /// <param name="db">得到数据库的当前图层</param>
        /// <returns></returns>
        public static LayerTableRecord GetCurrentlayer(Database db)
        {
            LayerTableRecord layer = new LayerTableRecord();

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                layer = tr.GetObject(db.Clayer, OpenMode.ForRead) as LayerTableRecord;

                tr.Commit();
            }

            return layer;
        }

        /// <summary>
        /// 设置为当前图层
        /// </summary>
        /// <param name="layer">图层对象</param>
        /// <param name="db">数据库对象</param>
        public static void SetCurrentLayer(LayerTableRecord layer, Database db)
        {
            if (layer.ObjectId != ObjectId.Null)
            {
                db.Clayer = layer.ObjectId;
            }
        }

        /// <summary>
        /// 新建一个图层
        /// </summary>
        /// <param name="strLayername">图层名</param>
        /// <param name="db">数据库名</param>
        /// <param name="bSetCur">是否设置为当前图层</param>
        /// <returns></returns>
        public static ObjectId CreateLayer(string strLayername, Database db, bool bSetCur = false)
        {
            ObjectId id = ObjectId.Null;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable table = tr.GetObject(db.LayerTableId, OpenMode.ForWrite) as LayerTable;
                if (null != table)
                {
                    if (!table.Has(strLayername)) // 存在就不再创建  
                    {
                        LayerTableRecord layer = new LayerTableRecord();
                        layer.Name = strLayername;

                        id = table.Add(layer);
                        tr.AddNewlyCreatedDBObject(layer, true);

                        if (bSetCur)
                        {
                            SetCurrentLayer(layer, db);
                        }
                    }

                }

                tr.Commit();
            }

            return id;
        }

        /// <summary>
        /// 根据图层名删除当前图层
        /// </summary>
        /// <param name="strDelLayer"></param>
        /// <param name="db"></param>
        public static void DeleteLayer(string strDelLayer, Database db)
        {
            ObjectId layerId = ObjectId.Null;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable table = tr.GetObject(db.LayerTableId, OpenMode.ForWrite) as LayerTable;
                if (null != table)
                {
                    LayerTableRecord curLayer = tr.GetObject(db.Clayer, OpenMode.ForRead) as LayerTableRecord;
                    if (curLayer.Name.ToLower() != strDelLayer.ToLower()) // 当前图层不可删除  
                    {
                        if (table.Has(strDelLayer)) // 存在就不再创建  
                        {
                            LayerTableRecord layer = new LayerTableRecord();
                            layer = tr.GetObject(table[strDelLayer], OpenMode.ForWrite) as LayerTableRecord;
                            if (layer != null)
                            {
                                if (!layer.IsErased)
                                {
                                    ObjectIdCollection idArr = new ObjectIdCollection();
                                    idArr.Add(layer.ObjectId);
                                    db.Purge(idArr); // 删除图层id  

                                    if (idArr.Count != 0) // 判断是否删除失败  
                                    {
                                        layer.Erase();
                                    }
                                }
                            }
                        }
                    }
                }

                tr.Commit();
            }
        }

        /// <summary>
        /// 删除图层上的所有实体
        /// </summary>
        /// <param name="layer">图层对象</param>
        /// <param name="db">数据库对象</param>
        public static void DeleteAllEntsOfLayer(LayerTableRecord layer, Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
                if (bt != null)
                {
                    foreach (ObjectId id in bt)
                    {
                        BlockTableRecord blk = tr.GetObject(id, OpenMode.ForWrite) as BlockTableRecord;
                        if (null == blk)
                            continue;

                        foreach (ObjectId idEnt in blk)
                        {
                            Entity ent = tr.GetObject(idEnt, OpenMode.ForWrite) as Entity;
                            if (null == ent)
                                continue;
                            if (ent.LayerId != layer.ObjectId)
                                continue;

                            ent.Erase();
                        }
                    }
                }

                tr.Commit();
            }
        }
#endregion

        #region 视口操作

        /// <summary>
        /// 获取数据库的所有视口
        /// </summary>
        /// <param name="db">数据库对象</param>
        /// <returns></returns>
        public static ViewportTableRecord GetCurViewPort(Database db)
        {
            ViewportTableRecord vport = new ViewportTableRecord();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                ViewportTable bt = tr.GetObject(db.ViewTableId, OpenMode.ForRead) as ViewportTable;

                vport = tr.GetObject(bt["*Active"], OpenMode.ForRead) as ViewportTableRecord;

                tr.Commit();
            }

            return vport;
        }
        #endregion

        #region 字典操作
        /// <summary>
        /// 添加一个实体到命名字典
        /// </summary>
        /// <param name="Obj">要添加到命名对象此点的对象</param>
        /// <param name="strDicName">词典记录名</param>
        /// <param name="db">数据库</param>
        public static void AddEntToNameDictionary(DBObject Obj, string strDicName, Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary Dict = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite) as DBDictionary;
                if (null != Dict)
                {
                    Dict.SetAt(strDicName, Obj);
                }

                tr.Commit();
            }
        }

        /// <summary>
        /// 获取命名字典中的实体
        /// </summary>
        /// <param name="strDicName">词典记录名</param>
        /// <param name="db">词典数据库</param>
        /// <returns>对象</returns>
        public static DBObject GetObjFromNOD(string strDicName, Database db)
        {
            DBObject obj = null;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary Dict = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead) as DBDictionary;
                if (null != Dict)
                {
                    obj = tr.GetObject(Dict.GetAt(strDicName), OpenMode.ForRead) as DBObject;
                }

                tr.Commit();
            }

            return obj;
        }

        /// <summary>
        /// 添加一个对象到命名对象词典
        /// </summary>
        /// <param name="dataObj">要添加到命名对象词典的对象</param>
        /// <param name="name">词典记录名</param>
        /// <param name="db">数据库</param>
        public void AddObjToNOD( DBObject dataObj, string name, Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary Dict = tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead) as DBDictionary;
                if (null != Dict)
                    Dict.SetAt(name, dataObj);

                tr.Commit();
            }
        }

        /// <summary>
        /// 添加一个对象到对象扩展词典
        /// </summary>
        /// <param name="Obj">要添加到扩展词典的对象</param>
        /// <param name="dbObj">词典对象的宿主</param>
        /// <param name="strDIcName">词典记录名</param>
        public static void AddObjToExtensionDictionary(DBObject Obj, DBObject dbObj, string strDIcName)
        {
            Database db = dbObj.Database;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                if (dbObj.ExtensionDictionary == new ObjectId())
                {
                    dbObj.CreateExtensionDictionary();

                    DBDictionary exDic = tr.GetObject(dbObj.ExtensionDictionary, OpenMode.ForWrite, false) as DBDictionary;

                    exDic.SetAt(strDIcName, Obj);
                }

                tr.Commit();
            }
        }

        /// <summary>
        /// 从目标字典扩展数据中读取一个实体  
        /// </summary>
        /// <param name="dbObj">词典对象的宿主</param>
        /// <param name="strDIcName">词典记录名</param>
        /// <returns>对象</returns>
        public static DBObject GetObjFromExDictionary(DBObject dbObj, string strDIcName )
        {
            DBObject obj = null;

            Database db = dbObj.Database;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                if (dbObj.ExtensionDictionary != new ObjectId())
                {
                    DBDictionary exDic = tr.GetObject(dbObj.ExtensionDictionary, OpenMode.ForWrite, false) as DBDictionary;

                    obj = tr.GetObject(exDic.GetAt(strDIcName), OpenMode.ForWrite) as DBObject;
                }

                tr.Commit();
            }

            return obj;
        }


        /// <summary>
        /// 添加对象到组字典
        /// </summary>
        /// <param name="idArr"></param>
        /// <param name="strGroupName"></param>
        /// <param name="db"></param>
        public void AddToGroup(ObjectIdCollection idArr, string strGroupName, Database db)
        {
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                Group group = new Group();
                foreach( ObjectId id in idArr)
                {
                    group.Append(id);
                }
                DBDictionary dic = GetObjFromNOD("ACAD_GROUP", db) as DBDictionary;
                dic.SetAt(strGroupName, group);
                tr.AddNewlyCreatedDBObject(group, true);

                tr.Commit();
            }
        }
        #endregion
    }
}
